package spring.data.jpa.repository.support;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.data.domain.Pageable;

import spring.data.jpa.repository.support.SearchFilter.Operator;

public class NativeSearchSupport extends FilterSupport{
	private String sql;

	private List<Object> sqlParams;

	public NativeSearchSupport(String sql) {
		this.sql = sql;
		this.sqlParams = new ArrayList<>();
	}

	public NativeSearchSupport(String sql, List<Object> sqlParams) {
		this.sql = sql;
		this.sqlParams = sqlParams;
	}

	public NativeSearchSupport(String sql, Object... sqlParams) {
		this.sql = sql;
		this.sqlParams = Arrays.asList(sqlParams);
	}

	public String getSql() {
		return sql;
	}

	public List<Object> getSqlParams() {
		return sqlParams;
	}
	
	public Object[] getSqlArrayParams() {
		return sqlParams.toArray(new Object[getParamsSize()]);
	}
	
	public int getParamsSize() {
		return getSqlParams() == null ? 0 :getSqlParams().size();
	}

	public String parseSql() {
		StringBuilder whereClause = new StringBuilder(" WHERE 1=1 ");
		int index = this.sqlParams.size() + 1;
		for (SearchFilter filter : this.andFilter) {
			whereClause.append("AND ");
			whereClause.append(filter.getFieldName());
			whereClause.append(" ");
			whereClause.append(filter.getOperator().getNativeCode());
			whereClause.append(" ");
			if (Operator.IN == filter.getOperator()) {

				@SuppressWarnings("unchecked")
				List<Object> paramValues = (List<Object>) filter.getValue();
				whereClause.append("(");
				for (int i = 0; i < paramValues.size(); i++) {
					whereClause.append("?");
					whereClause.append(index++);
					if (i != paramValues.size() - 1) {
						whereClause.append(",");
					}
					this.sqlParams.add(paramValues.get(i));
				}
				whereClause.append(")");
			} else if (Operator.LIKE == filter.getOperator()) {
				whereClause.append("?");
				whereClause.append(index++);
				whereClause.append(" ");
				this.sqlParams.add("%" + filter.getValue() + "%");
			} else {
				whereClause.append("?");
				whereClause.append(index++);
				whereClause.append(" ");
				this.sqlParams.add(filter.getValue());
			}
		}
		String handledSql = getSql().replace("%WHERE_CLAUSE%", whereClause.toString());
		this.sql = handledSql;
		return handledSql;
	}

	public String parseSql(Pageable page) {
		String handledSql = parseSql();

		long start = page.getOffset();
		long end = page.getOffset() + page.getPageSize();

		StringBuilder sqlBuffer = new StringBuilder();
		sqlBuffer.append("SELECT * FROM ( SELECT z_results.*,ROWNUM rm FROM ( ");
		sqlBuffer.append(handledSql);
		sqlBuffer.append(" ) z_results WHERE ROWNUM <= ").append(end).append(")");
		sqlBuffer.append(" WHERE rm > ").append(start);

		return sqlBuffer.toString();
	}
}
